package tetris;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.event.*;

import javax.swing.*;

/**
 * ��Ϸ���࣬�̳���JFrame��������Ϸ��ȫ�ֿ��ơ� �ں� 1, һ��GameCanvas�������ʵ�����ã� 2,
 * һ�����浱ǰ���(ErsBlock)ʵ������ã� 3, һ�����浱ǰ������壨ControlPanel��ʵ�������;
 */
public class MainFrame extends JFrame {
	/**
	 * ÿ����һ�мƶ��ٷ�
	 */
	public final static int PER_LINE_SCORE = 100;
	/**
	 * ����ٷ��Ժ�����
	 */
	public final static int PER_LEVEL_SCORE = PER_LINE_SCORE * 20;
	/**
	 * �������10��
	 */
	public final static int MAX_LEVEL = 10;
	/**
	 * Ĭ�ϼ�����5
	 */
	public final static int DEFAULT_LEVEL = 5;
	private GamePane canvas;
	private TetrisShape block;
	private boolean playing = false;
	private ControlPane ctrlPanel;
	private JMenuBar bar = new JMenuBar();
	private JMenu mGame = new JMenu("Game"), mControl = new JMenu("Control");
	private JMenuItem miNewGame = new JMenuItem("New Game"), miSetBlockColor = new JMenuItem("Set Block Color ..."), miSetBackColor = new JMenuItem(
			"Set Background Color ..."), miTurnHarder = new JMenuItem("Turn up the level"), miTurnEasier = new JMenuItem("Turn down the level"),
			miExit = new JMenuItem("Eixt"), miPlay = new JMenuItem("Play"), miPause = new JMenuItem("Pause"), miResume = new JMenuItem("Resume"),
			miStop = new JMenuItem("Stop");

	/**
	 * ����Ϸ��Ĺ��캯��
	 */
	public MainFrame() {
		super();
		this.setTitle("TETRIS");
		this.setSize(315, 392);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		createMenu();
		Container container = getContentPane();
		container.setLayout(new BorderLayout(6, 0));
		canvas = new GamePane(20, 12);
		ctrlPanel = new ControlPane(this);
		container.add(canvas, BorderLayout.CENTER);
		container.add(ctrlPanel, BorderLayout.EAST);
		addComponentListener(new ComponentAdapter() {
			public void componentResized(ComponentEvent ce) {
				canvas.fanning();
			}
		});
		canvas.fanning();
	}

	/**
	 * ��Ϸ����λ��
	 */
	public void reset() {
		ctrlPanel.reset();
		canvas.reset();
	}

	/**
	 * �ж���Ϸ�Ƿ��ڽ���
	 */
	public boolean isPlaying() {
		return playing;
	}

	/**
	 * �õ���ǰ��Ŀ�
	 */
	public TetrisShape getCurBlock() {
		return block;
	}

	/**
	 * �õ���ǰ����
	 */
	public GamePane getCanvas() {
		return canvas;
	}

	/**
	 * ��ʼ��Ϸ
	 */
	public void playGame() {
		play();
		ctrlPanel.setPlayButtonEnable(false);
		miPlay.setEnabled(false);
		ctrlPanel.requestFocus();
	}

	/**
	 * ��Ϸ��ͣ
	 */
	public void pauseGame() {
		if (block != null)
			block.pauseMove();
		ctrlPanel.setPauseButtonLabel(false);
		miPause.setEnabled(false);
		miResume.setEnabled(true);
	}

	/**
	 * ����ͣ�е���Ϸ����
	 */
	public void resumeGame() {
		if (block != null)
			block.resumeMove();
		ctrlPanel.setPauseButtonLabel(true);
		miPause.setEnabled(true);
		miResume.setEnabled(false);
		ctrlPanel.requestFocus();
	}

	/**
	 * ֹͣ��Ϸ
	 */
	public void stopGame() {
		playing = false;
		if (block != null)
			block.stopMove();
		miPlay.setEnabled(true);
		miPause.setEnabled(true);
		miResume.setEnabled(false);
		ctrlPanel.setPlayButtonEnable(true);
		ctrlPanel.setPauseButtonLabel(true);
	}

	/**
	 * �õ���ǰ��Ϸ�����õ���Ϸ�Ѷ�
	 */
	public int getLevel() {
		return ctrlPanel.getLevel();
	}

	/**
	 * ���û�������Ϸ�Ѷ�
	 */
	public void setLevel(int level) {
		if (level < 11 && level > 0)
			ctrlPanel.setLevel(level);
	}

	/**
	 * �õ���Ϸ���
	 */
	public int getScore() {
		if (canvas != null)
			return canvas.getScore();
		return 0;
	}

	/**
	 * �õ����ϴ�����������Ϸ��֣����Ժ󣬴˻������
	 */
	public int getScoreForLevelUpdate() {
		if (canvas != null)
			return canvas.getScoreForLevelUpdate();
		return 0;
	}

	/**
	 * �������ۼƵ�һ��������ʱ����һ�μ�
	 */
	public boolean levelUpdate() {
		int curLevel = getLevel();
		if (curLevel < MAX_LEVEL) {
			setLevel(curLevel + 1);
			canvas.resetScoreForLevelUpdate();
			return true;
		}
		return false;
	}

	/**
	 * ��Ϸ��ʼ
	 */
	private void play() {
		reset();
		playing = true;
		Thread thread = new Thread(new Game());
		thread.start();
	}

	/**
	 * ������Ϸ������
	 */
	private void reportGameOver() {
		JOptionPane.showMessageDialog(this, "Game Over!");
	}

	/**
	 * ���������ô��ڲ˵�
	 */
	private void createMenu() {
		bar.add(mGame);
		bar.add(mControl);
		mGame.add(miNewGame);
		mGame.addSeparator();
		mGame.add(miSetBlockColor);
		mGame.add(miSetBackColor);
		mGame.addSeparator();
		mGame.add(miTurnHarder);
		mGame.add(miTurnEasier);
		mGame.addSeparator();
		mGame.add(miExit);
		mControl.add(miPlay);
		mControl.add(miPause);
		mControl.add(miResume);
		mControl.add(miStop);
		setJMenuBar(bar);
		miPause.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, KeyEvent.CTRL_MASK));
		miResume.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0));
		miNewGame.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent ae) {
				stopGame();
				reset();
				setLevel(DEFAULT_LEVEL);
			}
		});
		miSetBlockColor.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent ae) {
				Color newFrontColor = JColorChooser.showDialog(MainFrame.this, "Set color for block", canvas.getBlockColor());
				if (newFrontColor != null)
					canvas.setBlockColor(newFrontColor);
			}
		});
		miSetBackColor.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent ae) {
				Color newBackColor = JColorChooser.showDialog(MainFrame.this, "Set color for block", canvas.getBackgroundColor());
				if (newBackColor != null)
					canvas.setBackgroundColor(newBackColor);
			}
		});
		miTurnHarder.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent ae) {
				int curLevel = getLevel();
				if (curLevel < MAX_LEVEL)
					setLevel(curLevel + 1);
			}
		});
		miTurnEasier.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent ae) {
				int curLevel = getLevel();
				if (curLevel > 1)
					setLevel(curLevel - 1);
			}
		});
		miExit.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent ae) {
				System.exit(0);
			}
		});
		miPlay.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent ae) {
				playGame();
			}
		});
		miPause.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent ae) {
				pauseGame();
			}
		});
		miResume.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent ae) {
				resumeGame();
			}
		});
		miStop.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent ae) {
				stopGame();
			}
		});
	}

	/**
	 * һ����Ϸ��̣�ʵ����Runnable�ӿ� һ����Ϸ��һ����ѭ���������ѭ���У�ÿ��100���룬
	 * �����Ϸ�еĵ�ǰ���Ƿ��Ѿ������ˣ����û�У� �ͼ���ȴ������ˣ��Ϳ���û��ȫ������У�
	 * ����о�ɾ����Ϊ��Ϸ�߼ӷ֣�ͬʱ������һ�� �µĵ�ǰ�飬�����Զ����䡣
	 * ���²���һ����ʱ���ȼ�黭����ϵ�һ���Ƿ��Ѿ� ��ռ�ˣ�����ǣ������ж�Game Over�ˡ�
	 */
	private class Game implements Runnable {
		public void run() {
			int col = (int) (Math.random() * (canvas.getCols() - 3)), style = TetrisShape.STYLES[(int) (Math.random() * 7)][(int) (Math.random() * 4)];
			while (playing) {
				if (block != null) { // ��һ��ѭ��ʱ��blockΪ��
					if (block.isAlive()) {
						try {
							Thread.sleep(100);
						} catch (InterruptedException ie) {
							ie.printStackTrace();
						}
						continue;
					}
				}
				checkFullLine(); // ����Ƿ���ȫ�������
				if (isGameOver()) { // �����Ϸ�Ƿ�Ӧ�ý�����
					miPlay.setEnabled(true);
					miPause.setEnabled(true);
					miResume.setEnabled(false);
					ctrlPanel.setPlayButtonEnable(true);
					ctrlPanel.setPauseButtonLabel(true);
					reportGameOver();
					return;
				}
				block = new TetrisShape(style, -1, col, getLevel(), canvas);
				block.start();
				col = (int) (Math.random() * (canvas.getCols() - 3));
				style = TetrisShape.STYLES[(int) (Math.random() * 7)][(int) (Math.random() * 4)];
				ctrlPanel.setTipStyle(style);
			}
		}

		/**
		 * ��黭�����Ƿ���ȫ������У�����о�ɾ��֮
		 */
		public void checkFullLine() {
			for (int i = 0; i < canvas.getRows(); i++) {
				int row = -1;
				boolean fullLineColorBox = true;
				for (int j = 0; j < canvas.getCols(); j++) {
					if (!canvas.getBox(i, j).isColorBox()) {
						fullLineColorBox = false;
						break;
					}
				}
				if (fullLineColorBox) {
					row = i--;
					canvas.removeLine(row);
				}
			}
		}

		/**
		 * �������Ƿ�ռ���ж���Ϸ�Ƿ��Ѿ������ˡ�
		 * 
		 * @return boolean, true-��Ϸ�����ˣ�false-��Ϸδ����
		 */
		private boolean isGameOver() {
			for (int i = 0; i < canvas.getCols(); i++) {
				TetrisCell box = canvas.getBox(0, i);
				if (box.isColorBox())
					return true;
			}
			return false;
		}
	}
}
